package cqu.zhaiyixin20215521.huarondao.slice.huarondaoPlay;

import cqu.zhaiyixin20215521.huarondao.ResourceTable;
import cqu.zhaiyixin20215521.huarondao.slice.pintuInitialize.Pintu;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.window.dialog.ToastDialog;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.media.camera.params.Face;
import ohos.media.image.PixelMap;

public class HuaRonDaoPlaySlice extends AbilitySlice {
    private PositionLayout tableFrame;
    private HuaRonDao huaRonDao;
    private TableLayout table;
    private ShapeElement border;
    private int dragDirection = 0, dragRow = 0, dragCol = 0;
    private AnimatorGroup animatorGroup;
    private AnimatorProperty[] animatorProperties;
    private Image[] shiftingImages;
    private final int RANDOM_WALK = 0, SHOW_ANSWER = 1, NO_AUTO = 2;
    private int isAuto = NO_AUTO; //是否自动
    private BackgroundHandler backgroundHandler;
    private PixelMap finalPiece;
    private PixelMap chosenPicture;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent((ComponentContainer) LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_ability_huarondao_play, null, false));
        tableFrame = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceTableFrame);
        table = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySlicePiecesTable);
        border = new ShapeElement(this, ResourceTable.Graphic_border);
        IntentParams intentParams = intent.getParams();
        Pintu pintu = (Pintu) intentParams.getParam("pintu");
        finalPiece = (PixelMap) intentParams.getParam("finalPiece");
        chosenPicture = (PixelMap) intentParams.getParam("chosenPicture");
        int[] numbers = new int[pintu.rowNum * pintu.colNum];
        PixelMap[] pixelMaps = new PixelMap[pintu.rowNum * pintu.colNum];
        for (int i = 0; i < pintu.size(); ++i) {
            if (pintu.get(i) == null) {
                numbers[i] = pintu.size()-1;
                pixelMaps[i] = null;
            } else {
                numbers[i] = pintu.get(i).number;
                pixelMaps[i] = pintu.get(i).pixelMap;
            }
        }
        huaRonDao = new HuaRonDao(pintu.rowNum, pintu.colNum, numbers);
        backgroundHandler = new BackgroundHandler(EventRunner.create(true), EventRunner.current());
        initPiecesTable(pixelMaps);
        initRandomWalkButton();
        initShowAnswerButton();
    }

    private void initPiecesTable(PixelMap[] pixelMaps) {
        //初始化长宽
        DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig();
        if (huaRonDao.rowNum >= huaRonDao.colNum) {
            config.height = AttrHelper.vp2px(this.getResourceManager().getDeviceCapability().width, this) * 19 / 20;
            config.width = config.height * huaRonDao.colNum / huaRonDao.rowNum;
        } else {
            config.width = AttrHelper.vp2px(this.getResourceManager().getDeviceCapability().width, this) * 19 / 20;
            config.height = config.width * huaRonDao.rowNum / huaRonDao.colNum;
        }
        tableFrame.setLayoutConfig(config);
        table.setRowCount(huaRonDao.rowNum);
        table.setColumnCount(huaRonDao.colNum);

        //初始化动画效果
        animatorGroup = new AnimatorGroup();
        animatorProperties = new AnimatorProperty[Math.max(huaRonDao.colNum, huaRonDao.rowNum) - 1];
        shiftingImages = new Image[Math.max(huaRonDao.colNum, huaRonDao.rowNum) - 1];
        for(int i = 0; i < animatorProperties.length; ++i) {
            animatorProperties[i] = new AnimatorProperty();
            Image image = new Image(this);
            image.setScaleMode(Image.ScaleMode.STRETCH);
            shiftingImages[i] = image;
        }
        animatorGroup.setStateChangedListener(new animationStateChangedListener());

        //初始化方格
        TableLayout.LayoutConfig pieceConfig = new TableLayout.LayoutConfig(config.width / huaRonDao.colNum, config.height / huaRonDao.rowNum);
        for (int i = 0; i < huaRonDao.rowNum * huaRonDao.colNum; ++i) {
            pieceConfig.rowSpec = TableLayout.specification(i / huaRonDao.colNum, 1);
            pieceConfig.columnSpec = TableLayout.specification(i % huaRonDao.colNum, 1);
            Image image = new Image(this);
            image.setScaleMode(Image.ScaleMode.STRETCH);
            image.setPixelMap(pixelMaps[i]);
            table.addComponent(image, i, pieceConfig);
            image.setDraggedListener(Component.DRAG_HORIZONTAL_VERTICAL, new pieceDraggedListener());
        }
    }

    //在滑动动画开始前，隐藏方块，初始化动画
    private int beforeAnimation(int direction, int row, int col, AnimatorProperty[] animatorProperties) {
        Image image = (Image) table.getComponentAt(row * huaRonDao.colNum + col);
        if (image.getPixelMap() == null) {
            return 0;
        } else {
            int row_next, col_next;
            switch (direction) {
                case HuaRonDao.UP:
                    row_next = row - 1;
                    col_next = col;
                    break;
                case HuaRonDao.DOWN:
                    row_next = row + 1;
                    col_next = col;
                    break;
                case HuaRonDao.LEFT:
                    row_next = row;
                    col_next = col - 1;
                    break;
                case HuaRonDao.RIGHT:
                    row_next = row;
                    col_next = col + 1;
                    break;
                default:
                    row_next = -1;
                    col_next = -1;
            }
            int index = beforeAnimation(direction, row_next, col_next, animatorProperties);
            Image shiftingImage = shiftingImages[index];
            shiftingImage.setPixelMap(image.getPixelMap());
            tableFrame.addComponent(shiftingImage, image.getWidth(), image.getHeight());
            shiftingImage.setPosition((int) image.getContentPositionX(), (int) image.getContentPositionY());
            AnimatorProperty animatorProperty = animatorProperties[index];
            animatorProperty.setTarget(shiftingImage)
                    .moveByY((row_next - row) * image.getWidth())
                    .moveByX((col_next - col) * image.getWidth());
            image.setVisibility(Component.INVISIBLE);
            return index + 1;
        }
    }

    //在移动动画结束后，清除动画，交换方块，展现方块
    private int afterAnimation(int direction, int row, int col, AnimatorProperty[] animatorProperty) {
        Image image = (Image) table.getComponentAt(row * huaRonDao.colNum + col);
        if (image.getPixelMap() == null) {
            return 0;
        } else {
            int row_next, col_next;
            switch (direction) {
                case HuaRonDao.UP:
                    row_next = row - 1;
                    col_next = col;
                    break;
                case HuaRonDao.DOWN:
                    row_next = row + 1;
                    col_next = col;
                    break;
                case HuaRonDao.LEFT:
                    row_next = row;
                    col_next = col - 1;
                    break;
                case HuaRonDao.RIGHT:
                    row_next = row;
                    col_next = col + 1;
                    break;
                default:
                    row_next = -1;
                    col_next = -1;
            }
            int index = afterAnimation(direction, row_next, col_next, animatorProperty);
            Image space = (Image) table.getComponentAt(row_next * huaRonDao.colNum + col_next);
            space.setPixelMap(image.getPixelMap());
            image.setPixelMap(null);
            image.setVisibility(Component.VISIBLE);
            Image shiftingImage = shiftingImages[index];
            tableFrame.removeComponent(shiftingImage);
            AnimatorProperty animator = animatorProperty[index];
            animator.reset();
            return index + 1;
        }
    }

    class pieceDraggedListener implements Component.DraggedListener {
        @Override
        public boolean onDragPreAccept(Component component, int dragDirection) {
            table.setEnabled(false);
            Image image = (Image) component;
            TableLayout.LayoutConfig layoutConfig = (TableLayout.LayoutConfig) image.getLayoutConfig();
            int row = layoutConfig.rowSpec.getMinSpan();
            int col = layoutConfig.columnSpec.getMinSpan();
            dragPiece(dragDirection, row, col);
            return true;
        }

        @Override
        public void onDragDown(Component component, DragInfo dragInfo) {
        }

        @Override
        public void onDragStart(Component component, DragInfo dragInfo) {
        }

        @Override
        public void onDragUpdate(Component component, DragInfo dragInfo) {
        }

        @Override
        public void onDragEnd(Component component, DragInfo dragInfo) {
        }

        @Override
        public void onDragCancel(Component component, DragInfo dragInfo) {
        }
    }

    private void dragPiece(int direction, int row, int col) {
        if(huaRonDao.shiftPiece(direction, row, col)) {
            HuaRonDaoPlaySlice.this.beforeAnimation(direction, row, col, animatorProperties);
            HuaRonDaoPlaySlice.this.dragDirection = direction;
            HuaRonDaoPlaySlice.this.dragRow = row;
            HuaRonDaoPlaySlice.this.dragCol = col;
            animatorGroup.runParallel(animatorProperties);
            animatorGroup.start();
        } else {
            table.setEnabled(true);
        }
    }

    class animationStateChangedListener implements Animator.StateChangedListener {
        @Override
        public void onStart(Animator animator) {
        }

        @Override
        public void onStop(Animator animator) {
            afterAnimation(HuaRonDaoPlaySlice.this.dragDirection, HuaRonDaoPlaySlice.this.dragRow, HuaRonDaoPlaySlice.this.dragCol, animatorProperties);
            table.setEnabled(true);
            checkWin();
            backgroundHandler.sendEvent(isAuto);
        }

        @Override
        public void onCancel(Animator animator) {
        }

        @Override
        public void onEnd(Animator animator) {
        }

        @Override
        public void onPause(Animator animator) {
        }

        @Override
        public void onResume(Animator animator) {
        }
    }

    private void initRandomWalkButton() {
        Button button = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceRandomWalkButton);
        Button showAnswerButton = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceShowAnswerButton);
        button.setClickedListener(component -> {
            switch (isAuto) {
                case NO_AUTO:
                    component.setAlpha(0.7F);
                    isAuto = RANDOM_WALK;
                    backgroundHandler.sendEvent(RANDOM_WALK);
                    break;
                case SHOW_ANSWER:
                    showAnswerButton.setAlpha(1);
                    component.setAlpha(0.7F);
                    isAuto = RANDOM_WALK;
                    break;
                case RANDOM_WALK:
                    component.setAlpha(1);
                    isAuto = NO_AUTO;
                    break;
            }
        });
    }

    private void initShowAnswerButton() {
        Button button = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceShowAnswerButton);
        Button randomWalkButton = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceRandomWalkButton);
        button.setClickedListener( component -> {
            switch (isAuto) {
                case NO_AUTO:
                    component.setAlpha(0.7F);
                    isAuto = SHOW_ANSWER;
                    backgroundHandler.sendEvent(SHOW_ANSWER);
                    break;
                case RANDOM_WALK:
                    randomWalkButton.setAlpha(1);
                    component.setAlpha(0.7F);
                    isAuto = SHOW_ANSWER;
                    break;
                case SHOW_ANSWER:
                    component.setAlpha(1);
                    isAuto = NO_AUTO;
                    break;
            }
        });
    }

    private class BackgroundHandler extends EventHandler {
        private final HuaRonDaoRandom huaRonDaoRandom;
        private final HuaRonDaoAnswer huaRonDaoAnswer;
        private final EventHandler callBackHandler;
        private boolean huaRonDaoAnswerHasInit = false;

        public BackgroundHandler(EventRunner runner, EventRunner uiRunner) throws IllegalArgumentException {
            super(runner);
            huaRonDaoRandom = new HuaRonDaoRandom(huaRonDao);
            huaRonDaoAnswer = new HuaRonDaoAnswer(huaRonDao.rowNum, huaRonDao.colNum);
            callBackHandler = new EventHandler(uiRunner) {
                @Override
                public void processEvent(InnerEvent event) {
                    if(event.eventId == RANDOM_WALK) {
                        if(!huaRonDao.allPiecesInPlace()) {
                            dragPiece(huaRonDaoRandom.direction, huaRonDaoRandom.pieceRow, huaRonDaoRandom.pieceCol);
                        }
                    } else if(event.eventId == SHOW_ANSWER) {
                        if(huaRonDaoAnswer.direction == -1) {
                            new ToastDialog(HuaRonDaoPlaySlice.this)
                                    .setText("无解")
                                    .show();
                        } else if(huaRonDaoAnswer.direction > 0) {
                            dragPiece(huaRonDaoAnswer.direction, huaRonDaoAnswer.paceRow, huaRonDaoAnswer.paceCol);
                        }
                    }
                }
            };
        }

        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if(event.eventId == RANDOM_WALK) {
                huaRonDaoRandom.update();
                callBackHandler.sendEvent(RANDOM_WALK);
            } else if(event.eventId == SHOW_ANSWER) {
                if(!huaRonDaoAnswerHasInit) {
                    huaRonDaoAnswerHasInit = true;
                    huaRonDaoAnswer.init();
                }
                huaRonDaoAnswer.next(huaRonDao);
                callBackHandler.sendEvent(SHOW_ANSWER);
            }
        }
    }

    private void checkWin() {
        if(huaRonDao.allPiecesInPlace()) {
            isAuto = NO_AUTO;
            findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySlicePage)
                    .setEnabled(false);
            TableLayout piecesTable = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySlicePiecesTable);
            Image finalImage = (Image) piecesTable.getComponentAt(huaRonDao.rowNum * huaRonDao.colNum - 1);
            Image image = new Image(this);
            image.setPixelMap(finalPiece);
            image.setScaleMode(Image.ScaleMode.STRETCH);
            image.setWidth(finalImage.getWidth());
            image.setHeight(finalImage.getHeight());
            image.setPosition((int) (finalImage.getContentPositionX() + finalImage.getWidth()), (int) finalImage.getContentPositionY());
            PositionLayout tableFrame = findComponentById(ResourceTable.Id_HuaRonDaoPlayAbilitySliceTableFrame);
            tableFrame.addComponent(image);
            AnimatorProperty finalPieceShifting = new AnimatorProperty()
                    .setTarget(image)
                    .moveByX(-finalImage.getWidth())
                    .setDuration(2000);
            Image image2 = new Image(this);
            image2.setPixelMap(chosenPicture);
            image2.setScaleMode(Image.ScaleMode.STRETCH);
            image2.setLayoutConfig(tableFrame.getLayoutConfig());
            image2.setAlpha(0);
            tableFrame.addComponent(image2);
            AnimatorProperty initialPictureRecovering = new AnimatorProperty()
                    .setTarget(image2)
                    .alpha(1)
                    .setDuration(2000);
            AnimatorGroup ag = new AnimatorGroup();
            ag.runSerially(finalPieceShifting, initialPictureRecovering);
            ag.start();
        }
    }

}
